home *** CD-ROM | disk | FTP | other *** search
/ ShareWare OnLine 2 / ShareWare OnLine Volume 2 (CMS Software)(1993).iso / util2 / pgp22src.zip / SRC / LANGUAGE.C < prev    next >
C/C++ Source or Header  |  1993-03-07  |  9KB  |  416 lines

  1. /*
  2.  *    language.c - Foreign language translation for PGP
  3.  *    Finds foreign language "subtitles" for English phrases 
  4.  *    in external foriegn language text file.
  5.  */
  6.  
  7. #include <stdio.h>
  8. #include <stdlib.h>
  9. #include <string.h>
  10. #include <ctype.h>
  11. #include "usuals.h"
  12. #include "fileio.h"
  13. #include "language.h"
  14. #include "pgp.h"
  15. #include "charset.h"
  16.  
  17. #define SUBTITLES_FILE    "language.txt"
  18. #define LANG_INDEXFILE    "language.idx"
  19.  
  20. #define    STRBUFSIZE        2048
  21.  
  22. char language[16] = "en";    /* The language code, defaults to English */
  23. static char    *strbuf;
  24. static char    lang[16];    /* readstr sets this to the language id of the msg it last read */
  25. static int    subtitles_available = 0;
  26. static int line = 0;
  27. /*    subtitles_available is used to determine if we know whether the special
  28.     subtitles_file exists.  subtitles_available has the following values:
  29.     0  = first time thru, we don't yet know if subtitles_file exists.
  30.     1  = we have already determined that subtitles_file exists.
  31.     -1 = we have already determined that subtitles_file does not exist.
  32. */
  33.  
  34. #define    NEWLINE        0
  35. #define    COMMENT        1
  36. #define    INSTRING    2
  37. #define    ESCAPE        3
  38. #define    IDENT        4
  39. #define    DONE        5
  40. #define    ERROR        6
  41. #define    ERR1        7
  42.  
  43. /* Look for and return a quoted string from the file.
  44.  * If nlabort is true, return failure if we find a blank line
  45.  * before we find the opening quote.
  46.  */
  47. static char    *
  48. readstr (FILE *f, char *buf, int nlabort)
  49. {    int        c, d;
  50.     char *p = buf;
  51.     int state = NEWLINE;
  52.     int i = 0;
  53.     
  54.     while ((c = getc(f)) != EOF)
  55.     {
  56.         if (c == '\r')
  57.             continue;
  58.         /* line numbers are only incremented when creating index file */
  59.         if (line && c == '\n')
  60.             ++line;
  61.         switch (state)
  62.         {
  63.             case NEWLINE:
  64.                 switch(c)
  65.                 {
  66.                     case '#': state = COMMENT; break;
  67.                     case '"': state = INSTRING; break;
  68.                     case '\n':
  69.                         if (nlabort)
  70.                         {    *buf = '\0';
  71.                             return(buf);
  72.                         }
  73.                     default:
  74.                         if (i == 0 && isalnum(c))
  75.                         {
  76.                             state = IDENT;
  77.                             lang[i++] = c;
  78.                             break;
  79.                         }
  80.                         if (!isspace(c))
  81.                         {
  82.                             fprintf(stderr, "language.txt:%d: syntax error\n", line);
  83.                             state = ERROR;
  84.                         }
  85.                 }
  86.                 break;
  87.             case COMMENT:
  88.                 if (c == '\n')
  89.                     state = NEWLINE;
  90.                 break;
  91.             case INSTRING:
  92.                 switch(c)
  93.                 {
  94.                     case '\\': state = ESCAPE; break;
  95.                     case '"': state = DONE; break;
  96.                     default: *p++ = c;
  97.                 }
  98.                 break;
  99.             case ESCAPE:
  100.                 switch (c)
  101.                 {
  102.                     case 'n':    *p++ = '\n';    break;
  103.                     case 'r':    *p++ = '\r';    break;
  104.                     case 't':    *p++ = '\t';    break;
  105.                     case 'e':    *p++ = '\033';    break;
  106.                     case 'a':    *p++ = '\007';    break;
  107.                     case '#':
  108.                     case '"':
  109.                     case '\\':    *p++ = c; break;
  110.                     case '\n':    break;
  111.                     case '0':
  112.                             d = 0;
  113.                             while ((c = fgetc(f)) >= '0' && c <= '7')
  114.                                 d = 8 * d + c - '0';
  115.                             *p++ = d;
  116.                             ungetc(c, f);
  117.                             break;
  118.                     default:
  119.                             fprintf(stderr, "language.txt:%d: illegal escape sequence: '\\%c'\n", line, c);
  120.                             break;
  121.                 }
  122.                 state = INSTRING;
  123.                 break;
  124.             case IDENT:        /* language identifier */
  125.                 if (c == ':') {
  126.                     state = NEWLINE;
  127.                     break;
  128.                 }
  129.                 if (c == '\n' && strncmp(lang, "No translation", 14) == 0)
  130.                 {
  131.                     i = 0;
  132.                     state = NEWLINE;
  133.                     break;
  134.                 }
  135.                 lang[i++] = c;
  136.                 if (i == 15 || !isalnum(c) && !isspace(c))
  137.                 {
  138.                     lang[i] = '\0';
  139.                     fprintf(stderr, "language.txt:%d: bad language identifier: '%s'\n", line, lang);
  140.                     state = ERROR;
  141.                     i = 0;
  142.                 }
  143.                 break;
  144.             case DONE:
  145.                 if (c == '\n')
  146.                 {
  147.                     lang[i] = '\0';
  148.                     *p = '\0';
  149.                     return(buf);
  150.                 }
  151.                 if (!isspace(c))
  152.                 {
  153.                     fprintf(stderr, "language.txt:%d: extra characters after '\"'\n", line);
  154.                     state = ERROR;
  155.                 }
  156.                 break;
  157.             case ERROR:
  158.                 if (c == '\n')
  159.                     state = ERR1;
  160.                 break;
  161.             case ERR1:
  162.                 state = (c == '\n' ? NEWLINE : ERROR);
  163.                 break;
  164.         }
  165.     }
  166.     if (state != NEWLINE)
  167.         fprintf(stderr, "language.txt: unexpected EOF\n");
  168.     return(NULL);
  169. }
  170.  
  171. #ifdef TEST
  172. main()
  173. {
  174.     char buf[2048];
  175.  
  176.     line = 1;
  177.     while (readstr(stdin, buf, 0)) {
  178.         printf("\nen: <%s>\n", buf);
  179.         while (readstr(stdin, buf, 1) && *buf != '\0')
  180.             printf("%s: <%s>\n", lang, buf);
  181.     }
  182.     exit(0);
  183. }
  184. #else
  185.  
  186. static struct indx_ent {
  187.     word32    crc;
  188.     long    offset;
  189. } *indx_tbl = NULL;
  190.  
  191. static int max_msgs = 0;
  192. static int nmsg = 0;
  193.  
  194. static FILE *langf;
  195.  
  196. static void init_lang(void);
  197.  
  198. static int make_indexfile(char *);
  199. word32 crcupdate(byte, word32);
  200. void init_crc();
  201.  
  202. /*
  203.  * uses 24-bit CRC function from armor.c
  204.  */
  205. static word32
  206. message_crc(char *s)
  207. {
  208.     word32 crc = 0;
  209.  
  210.     while (*s)
  211.         crc = crcupdate(*s++, crc);
  212.     return(crc);
  213. }
  214.  
  215. /*
  216.  * lookup file offset in indx_tbl
  217.  */
  218. static long
  219. lookup_offset(word32 crc)
  220. {
  221.     int i;
  222.     
  223.     for (i = 0; i < nmsg; ++i)
  224.         if (indx_tbl[i].crc == crc)
  225.             return(indx_tbl[i].offset);
  226.     return(-1);
  227. }
  228.  
  229.  
  230. /*
  231.  * return foreign translation of s
  232.  */
  233. char *
  234. PSTR (char *s)
  235. {
  236.     long filepos;
  237.  
  238.     if (subtitles_available == 0)
  239.         init_lang();
  240.     if (subtitles_available < 0)
  241.         return(s);
  242.  
  243.     filepos = lookup_offset(message_crc(s));
  244.     if (filepos == -1)
  245.         return(s);
  246.     else
  247.     {
  248.         fseek(langf, filepos, SEEK_SET);
  249.         readstr(langf, strbuf, 1);
  250.     }
  251.  
  252.     if (strbuf[0] == '\0')
  253.         return(s);
  254.  
  255.     for (s = strbuf; *s; ++s)
  256.         *s = EXT_C(*s);
  257.     return(strbuf);
  258. }
  259.  
  260.  
  261. static struct {
  262.     long lang_fsize;    /* size of language.txt */
  263.     char lang[16];        /* language identifier */
  264.     int nmsg;            /* number of messages */
  265. } indx_hdr;
  266.  
  267.  
  268. /*
  269.  * initialize the index table: read it from language.idx or create
  270.  * a new one and write it to the index file. A new index file is
  271.  * created if the language set in config.pgp doesn't match the one
  272.  * in language.idx or if the size of language.txt has changed.
  273.  */
  274. static void
  275. init_lang()
  276. {
  277.     char indexfile[MAX_PATH];
  278.     char subtitles_file[MAX_PATH];
  279.     FILE *indexf;
  280.  
  281.     if (strcmp(language, "en") == 0)
  282.     {    subtitles_available = -1;
  283.         return;        /* use default messages */
  284.     }
  285.  
  286.     buildfilename (subtitles_file, SUBTITLES_FILE);
  287.     if ((langf = fopen(subtitles_file, FOPRTXT)) == NULL)
  288.     {
  289.         subtitles_available = -1;
  290.         return;
  291.     }
  292.     init_crc();
  293.     if ((strbuf = (char *) malloc(STRBUFSIZE)) == NULL)
  294.     {
  295.         fprintf(stderr, "Not enough memory for foreign subtitles\n");
  296.         fclose(langf);
  297.         subtitles_available = -1;
  298.         return;
  299.     }
  300.     buildfilename(indexfile, LANG_INDEXFILE);
  301.     if ((indexf = fopen(indexfile, FOPRBIN)) != NULL)
  302.     {
  303.         if (fread(&indx_hdr, 1, sizeof(indx_hdr), indexf) == sizeof(indx_hdr) &&
  304.             indx_hdr.lang_fsize == fsize(langf) &&
  305.             strcmp(indx_hdr.lang, language) == 0)
  306.         {
  307.             nmsg = indx_hdr.nmsg;
  308.             indx_tbl = (struct indx_ent *) malloc(nmsg * sizeof(struct indx_ent));
  309.             if (indx_tbl == NULL)
  310.             {
  311.                 fprintf(stderr, "Not enough memory for foreign subtitles\n");
  312.                 fclose(indexf);
  313.                 fclose(langf);
  314.                 subtitles_available = -1;
  315.                 return;
  316.             }
  317.             if (fread(indx_tbl, sizeof(struct indx_ent), nmsg, indexf) != nmsg)
  318.             {
  319.                 free(indx_tbl);    /* create a new one */
  320.                 indx_tbl = NULL;
  321.             }
  322.         }
  323.         fclose(indexf);
  324.     }
  325.     if (indx_tbl == NULL && make_indexfile(indexfile) < 0)
  326.     {
  327.         fclose(langf);
  328.         subtitles_available = -1;
  329.     }
  330.     else
  331.         subtitles_available = 1;
  332. }
  333.  
  334.  
  335. static int
  336. make_indexfile(char *indexfile)
  337. {
  338.     FILE *indexf;
  339.     long filepos;
  340.     int total_msgs = 0;
  341.     char *res;
  342.  
  343.     if (verbose)    /* must be set in config.pgp */
  344.         fprintf(stderr, "Creating language index file '%s' for language \"%s\"\n",
  345.                 indexfile, language);
  346.     rewind(langf);
  347.     indx_hdr.lang_fsize = fsize(langf);
  348.     strncpy(indx_hdr.lang, language, 15);
  349.     init_crc();
  350.     line = 1;
  351.     nmsg = 0;
  352.     while (readstr(langf, strbuf, 0))
  353.     {
  354.         if (nmsg == max_msgs)
  355.         {
  356.             if (max_msgs)
  357.             {    max_msgs *= 2;
  358.                 indx_tbl = (struct indx_ent *) realloc(indx_tbl, max_msgs *
  359.                             sizeof(struct indx_ent));
  360.             }
  361.             else
  362.             {    max_msgs = 400;
  363.                 indx_tbl = (struct indx_ent *) malloc(max_msgs *
  364.                             sizeof(struct indx_ent));
  365.             }
  366.             if (indx_tbl == NULL)
  367.             {
  368.                 fprintf(stderr, "Not enough memory for foreign subtitles\n");
  369.                 return(-1);
  370.             }
  371.         }
  372.         ++total_msgs;
  373.         indx_tbl[nmsg].crc = message_crc(strbuf);
  374.         if (lookup_offset(indx_tbl[nmsg].crc) != -1)
  375.             fprintf(stderr, "language.txt:%d: Message CRC not unique: \"%s\"\n",
  376.                     line, strbuf);
  377.         do
  378.         {
  379.             filepos = ftell(langf);
  380.             res = readstr (langf, strbuf, 1);        /* Abort if find newline first */
  381.         } while (res && strbuf[0] != '\0' && strcmp(language, lang) != 0);
  382.  
  383.         if (res == NULL)
  384.             break;
  385.         if (strbuf[0] == '\0')    /* No translation */
  386.             continue;
  387.  
  388.         indx_tbl[nmsg].offset = filepos;
  389.         ++nmsg;
  390.         do
  391.             res = readstr (langf, strbuf, 1);        /* Abort if find newline first */
  392.         while (res && strbuf[0] != '\0');
  393.     }
  394.     line = 0;
  395.     indx_hdr.nmsg = nmsg;
  396.     if (nmsg == 0)
  397.     {    fprintf(stderr, "No translations available for language \"%s\"\n\n",
  398.                 language);
  399.         return(-1);
  400.     }
  401.     if (verbose || total_msgs != nmsg)
  402.         fprintf(stderr, "%d messages, %d translations\n\n", total_msgs, nmsg);
  403.  
  404.     if ((indexf = fopen(indexfile, FOPWBIN)) == NULL)
  405.         fprintf(stderr, "Cannot create %s\n", indexfile);
  406.     else
  407.     {
  408.         fwrite(&indx_hdr, 1, sizeof(indx_hdr), indexf);
  409.         fwrite(indx_tbl, sizeof(struct indx_ent), nmsg, indexf);
  410.         if (ferror(indexf) || fclose(indexf))
  411.             fprintf(stderr, "error writing %s\n", indexfile);
  412.     }
  413.     return(0);
  414. }
  415. #endif /* TEST */
  416.